import React, { useState, useRef, useContext, useCallback, useEffect } from 'react';
import {
  Icon,
  Tooltip,
  Modal,
  message,
  Divider,
  Spin,
  Form,
  Input,
  Typography,
  Dropdown,
  Menu,
} from 'antd';
import { useRequest } from 'ahooks';
import isPlainObject from 'lodash/isPlainObject';
import Tree, { FilteringContainer, renderers } from 'react-virtualized-tree';
import last from 'lodash/last';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import classnames from 'classnames';
import { getViewPort } from '@/utils/utils';
// eslint-disable-next-line import/no-named-default
import { default as TransformerContext } from '@/pages/Transformer/context';
import Context from './context';
import { getNodeById, getAttrPath, serialize } from './utils';
import request from '@/utils/request';
import Node from './components/Node';
import styles from './styles.less';
import SquareButton from '@/components/SquareButton';
import useModal from '@/hooks/UseModal';
import { SmallFormLayout } from '@/layouts/Form';
import CodeEditor from '@/components/CodeEditor';
import IconFont from '@/components/IconFont';
import { default as TargetContext } from '@/pages/Transformer/components/TargetPanel/targetContext';
import { contains, TreeFilter } from '../NodePathSelect/utils';
import useCopyToClipboard from '@/hooks/useCopyToClipboard';
import { renderPath } from '@/components/PathInput';

const { Expandable } = renderers;
const { Text } = Typography;

function isActived(current, sourceNodePath) {
  return (
    Array.isArray(get(current, 'nodePath')) && isEqual(get(current, 'nodePath'), sourceNodePath)
  );
}

function stringToJson(ref, format) {
  const editor = ref.current;

  if (editor.hasError()) {
    message.error(`不是合法的${format}格式`);
    return Promise.reject();
  }

  return request.post('/transform/parseSourceTree', {
    data: { format, message: editor.getValue() },
  });
}

function getHeight() {
  const { height } = getViewPort(false);
  const $header = document.getElementById('layout-header');
  const $tabsNav = document.querySelector('.layout-tabs-nav');

  return (
    height -
    ($header === null ? 0 : $header.offsetHeight) -
    ($tabsNav === null ? 0 : $tabsNav.offsetHeight) -
    16 * 2 -
    48 -
    12 * 2 -
    37
  );
}

const height = getHeight();

export const validationResult = {
  success: false,
  errors: [
    {
      fieldName: 'orderNo',
      fieldPath: "$['request']['order']['orderNo']",
      errorMessage: '不存在或为null',
      humanReadableErrorMessage: 'orderNo不存在或为null',
    },
    {
      fieldName: 'customerEmail',
      fieldPath: "$['request']['customer']['customerEmail']",
      errorMessage: '不满足邮箱格式',
      humanReadableErrorMessage: 'customerEmail不满足邮箱格式',
    },
  ],
};

function SourceEditor({ form }) {
  const { getFieldDecorator, getFieldValue, validateFields } = form;
  const { state, dispatch } = useContext(Context);
  const { data, globalToggle } = state;

  const { state: Tstate = {}, dispatch: Tdispatch } = useContext(TransformerContext);
  const { sourceType, sourceFormat, sourceMessage } = Tstate;
  const { state: TargetState = {}, dispatch: Targetdispatch } = useContext(TargetContext);

  const [visible, setVisible] = useState(false);
  const [_state, copyToClipboard] = useCopyToClipboard();

  const editorRef = useRef();

  const { visible: fromCodeModalVisible, showModal, hideModal } = useModal();
  const [fromCodeModalLoading, setFromCodeModalLoading] = useState(false);

  // 展示源配置面板
  const showSourcePanel = useCallback(
    data => {
      const tree = serialize([data])[0];
      dispatch({
        type: 'set_the_whole_tree',
        payload: { data: tree },
      });
    },
    [dispatch]
  );

  // 展示默认源配置面板
  const showDefaultSourcePanel = useCallback(() => {
    const data = {
      nodeName: 'root',
      nodeType: 'Object',
      nodePath: [],
      children: [],
    };
    showSourcePanel(data);
  }, [showSourcePanel]);

  const { loading, run } = useRequest(() => stringToJson(editorRef, sourceFormat), {
    manual: true,
    onSuccess: data => {
      setVisible(false);

      if (isPlainObject(data)) {
        showSourcePanel(data);

        Tdispatch({
          type: 'update',
          payload: {
            sourceMessage: editorRef.current.getValue(),
            sourceFormat,
          },
        });
      } else {
        message.error('预期返回约定格式的对象');
      }
    },
  });

  // 初始化校验失败报文
  const { loading: loading2, run: run2 } = useRequest(
    () => {
      return request.post('/transform/parseSourceTree', {
        data: { format: 'JSON', message: JSON.stringify(validationResult) },
      });
    },
    {
      manual: true,
      onSuccess: data => showSourcePanel(data),
    }
  );

  useEffect(() => {
    if (data === null && sourceType === 'VALIDATE_FAILURE') {
      run2();
    }
  }, [data, run2, sourceType]);

  function generateTreeFromCode() {
    validateFields((err, _values) => {
      if (err) return;
      const javaClassName = getFieldValue('javaClassName');
      setFromCodeModalLoading(true);
      request
        .post(`/transform/parseSourceTreeFromCode?className=${javaClassName}`)
        .then(({ message }) => {
          hideModal();
          setVisible(true);
          editorRef.current.setMode('json');
          editorRef.current.setValue(message);
        })
        .finally(() => setFromCodeModalLoading(false));
    });
  }

  return (
    <div className={styles.jsonEditor}>
      <div className={classnames(styles.toolbar, 'clearfix')}>
        <div className="ml-2 pull-left main-title" style={{ lineHeight: '40px' }}>
          源报文树
        </div>
        <div className="pull-right">
          <Tooltip title="清空源报文">
            <IconFont
              type="icon-cache"
              className={styles.command}
              style={{
                fontSize: 18,
                paddingLeft: 14.5,
                paddingRight: 14.5,
                paddingTop: 11,
                paddingBottom: 13,
                verticalAlign: 'top',
              }}
              onClick={() => {
                dispatch({
                  type: 'set_the_whole_tree',
                  payload: { data: null },
                });
                message.success('清空成功');
              }}
            />
          </Tooltip>

          <Divider type="vertical" />

          <Tooltip title="导入源报文">
            <Icon type="upload" className={styles.command} onClick={() => setVisible(true)} />
          </Tooltip>
          <Divider type="vertical" />
          <Tooltip title={globalToggle.status ? '全部收起' : '全部展开'}>
            <Icon
              type={globalToggle.status ? 'minus-square' : 'plus-square'}
              className={styles.command}
              onClick={() =>
                dispatch({ type: 'open_or_close_node', payload: !globalToggle.status })
              }
            />
          </Tooltip>
        </div>
      </div>
      <Spin spinning={loading2}>
        <div className={classnames(styles.body)} style={{ height: height + 37 + 32 + 12 }}>
          {!data ? (
            <div
              style={{
                height: '90%',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
              }}
            >
              <SquareButton
                onClick={() => setVisible(true)}
                style={{ marginRight: '16px' }}
                icon="upload"
                text="导入源报文"
              />
              <SquareButton
                style={{ marginRight: '16px' }}
                onClick={showDefaultSourcePanel}
                icon="plus"
                text="手动创建"
              />
              <SquareButton onClick={showModal} icon="code" text="从Java类生成" />
            </div>
          ) : (
            <FilteringContainer nodes={[data]} indexSearch={TreeFilter}>
              {({ nodes }) => (
                <ul className={styles.wtree} style={{ height }}>
                  <Tree
                    nodeMarginLeft={20}
                    nodes={nodes}
                    onChange={nodes =>
                      dispatch({ type: 'set_the_whole_tree', payload: { data: nodes[0] } })
                    }
                  >
                    {({ style, node, ...rest }) => {
                      const dotted =
                        Array.isArray(get(node, 'nodePath')) &&
                        isEqual(get(node, 'nodePath'), get(Tstate, 'sourceNodePath'));

                      const handleSelect = e => {
                        const { target } = e;
                        if (target && target.classList.contains('tgIcon')) {
                          return;
                        }
                        e.stopPropagation();

                        const targetNodePath = get(Tstate, 'targetNodePath');
                        const sourceNodePath = get(node, 'nodePath');

                        if (!Array.isArray(sourceNodePath)) {
                          throw new Error(`源报文${node.nodeName}节点的nodePath不是数组`);
                        }

                        Tdispatch({
                          type: 'quick_mapping_record_source',
                          payload: {
                            sourceNodePath,
                          },
                        });

                        if (!dotted) {
                          message.success(`选中: ${node.nodeName}`);
                        }

                        // 凑齐一对
                        if (
                          Array.isArray(sourceNodePath) &&
                          targetNodePath !== null &&
                          targetNodePath !== undefined
                        ) {
                          Targetdispatch({
                            type: 'quick_mapping',
                            payload: {
                              targetNodePath,
                              sourceNodePath,
                            },
                          });
                        }
                      };

                      return (
                        <Dropdown
                          trigger={['contextMenu']}
                          overlay={
                            <Menu>
                              <Menu.Item
                                onClick={() => {
                                  message.success(`拷贝路径: ${node.nodeName}`);
                                  copyToClipboard(renderPath(node.nodePath));
                                }}
                              >
                                <Icon type="copy" />
                                拷贝节点路径
                              </Menu.Item>
                            </Menu>
                          }
                        >
                          <div
                            style={{ ...style, paddingLeft: style.marginLeft + 24, marginLeft: 0 }}
                            className={classnames(styles.row, {
                              [styles.actived]: isActived(node, get(Tstate, 'sourceNodePath')),
                            })}
                            onClick={handleSelect}
                          >
                            <Expandable
                              node={node}
                              {...rest}
                              iconsClassNameMap={{
                                expanded: `tgIcon icon-arrow-down ${styles.switcher}`,
                                collapsed: `tgIcon icon-arrow-right ${styles.switcher}`,
                                // lastChild: 'mi mi-insert-drive-file',
                              }}
                            >
                              <Node
                                handleSelect={handleSelect}
                                nodePath={getAttrPath([data], k => k.id === node.id)}
                                current={node}
                                parentId={last(node.parents)}
                                parent={getNodeById([data], last(node.parents))}
                                offset={style.marginLeft}
                              />
                            </Expandable>
                          </div>
                        </Dropdown>
                      );
                    }}
                  </Tree>
                </ul>
              )}
            </FilteringContainer>
          )}
        </div>
      </Spin>

      <Modal
        title="从Java类生成"
        width={550}
        visible={fromCodeModalVisible}
        onOk={() => generateTreeFromCode()}
        okButtonProps={{
          loading: fromCodeModalLoading,
        }}
        onCancel={hideModal}
        destroyOnClose
      >
        <Form.Item label="Java类路径" {...SmallFormLayout}>
          {getFieldDecorator('javaClassName', {
            rules: [
              {
                required: true,
                message: '类路径不能为空',
              },
            ],
          })(
            <Input
              allowClear
              placeholder="com.iwhalecloud.tangram.standalone.example.OrderQueryDTO"
              addonAfter={
                <Text
                  className={styles.copyable}
                  copyable={{ text: getFieldValue('javaClassName') }}
                />
              }
            />
          )}
        </Form.Item>
      </Modal>

      <Modal
        visible={visible}
        width={780}
        title={`导入${sourceFormat}`}
        onOk={() => run()}
        onCancel={() => setVisible(false)}
        destroyOnClose
        okButtonProps={{
          loading,
        }}
      >
        <CodeEditor ref={editorRef} data={sourceMessage} mode={sourceFormat} />
      </Modal>
    </div>
  );
}

export default Form.create()(SourceEditor);
